package com.erp.framework.model.ejb;

import java.sql.Connection;
import java.util.Collection;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.transaction.UserTransaction;

import com.erp.framework.SimpleConstants;
import com.erp.framework.exceptions.CreateRecordException;
import com.erp.framework.exceptions.DeleteRecordException;
import com.erp.framework.exceptions.FindRecordException;
import com.erp.framework.exceptions.ModifyRecordException;
import com.erp.framework.model.bizLogic.SimpleBaseBizLogic;
import com.erp.framework.model.criteria.SimpleBaseSrchCriteria;
import com.erp.framework.model.dao.ServiceLocator;
import com.erp.framework.model.dao.SimpleBaseDao;
import com.erp.framework.model.pk.SimpleBasePk;
import com.erp.framework.model.vo.SimpleBaseVo;
import com.erp.framework.util.logger.Logger;

public class SimpleBaseSessionEjb implements SessionBean, SimpleConstants {
    public SessionContext sessionContext = null;
    protected SimpleBaseBizLogic bizLogic = null;

    public SimpleBaseSessionEjb() {
        Logger.setLogLevelFromSystem();
        Logger.setLogTimestampFromSystem();
        Logger.setLogToFileFromSystem();        
    }

    public int findTotal(SimpleBaseVo model, SimpleBaseSrchCriteria criteria) throws FindRecordException {
        int total = 0;
        SimpleBaseDao dao = null;
        Connection conn = null;
        ServiceLocator srvLocator = null;
        
        try {
            srvLocator = ServiceLocator.getInstance();
            conn = srvLocator.getDSDBConnection();
            dao = (SimpleBaseDao)model.getDaoType().newInstance();
            total = dao.findTotal(model, criteria, conn);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        } finally {
            try{
                conn.close();
            }catch(Exception e){
                
            }
        }
        
        return total;
    }
    
    public Collection findByCriteria(SimpleBaseVo model, SimpleBaseSrchCriteria criteria, int fetch_size, int start_idx)
    throws FindRecordException {
        Connection conn = null;
        Collection masterCollection = null;
        try{
            beforeFindByCriteria(model, criteria);
        } catch (Exception e){
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        }
    
        try {
            ServiceLocator srvLocator = ServiceLocator.getInstance();            
            SimpleBaseDao dao = (SimpleBaseDao) model.getDaoType().newInstance();
            conn = srvLocator.getDSDBConnection();
    
            beforeFindByCriteriaWithConn(model, criteria, conn);
            masterCollection = dao.findByCriteria(model, criteria, fetch_size, start_idx, conn);
            afterFindByCriteriaWithConn(model, criteria, masterCollection, conn);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        } finally {            
            try {
                conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }
    
        try{
            afterFindByCriteria(model, criteria, masterCollection);
        } catch (Exception e){
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        }
    
        return masterCollection;
    }
    
    protected void beforeFindByCriteria(SimpleBaseVo bizModel, SimpleBaseSrchCriteria criteria)
    throws Exception
    {

    }

    protected void afterFindByCriteria(SimpleBaseVo bizModel, SimpleBaseSrchCriteria criteria, Collection collection)
    throws Exception
    {

    }

    protected void beforeFindByCriteriaWithConn(SimpleBaseVo bizModel, SimpleBaseSrchCriteria criteria, Connection conn)
    throws Exception
    {

    }

    protected void afterFindByCriteriaWithConn(SimpleBaseVo bizModel, SimpleBaseSrchCriteria criteria, Collection collection, Connection conn)
    throws Exception
    {

    }
    
    public void getBizLogicTypeFromVo(SimpleBaseVo model) throws Exception{
        try{
            if(model.getBizLogicType() != null){
                bizLogic = (SimpleBaseBizLogic) model.getBizLogicType().newInstance();
            }
        }catch(Exception e){
            throw e;
        }
    }
    
    public Collection findByCriteria(SimpleBaseVo model, Object criteria) throws FindRecordException {

        Connection conn = null;
        // ServiceLocator srvLocator = new ServiceLocator();
        ServiceLocator srvLocator = ServiceLocator.getInstance();
        Collection masterCollection = null;
        try {            
            SimpleBaseDao dao = (SimpleBaseDao) model.getDaoType().newInstance();
            conn = srvLocator.getDSDBConnection();
            masterCollection = dao.findByCriteria(criteria, conn);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }
        return masterCollection;
    }

    public SimpleBaseVo findByPrimaryKey(SimpleBaseVo model, SimpleBasePk pk) throws FindRecordException {

        Connection conn = null;
        SimpleBaseVo targetModel = null;
        // ServiceLocator srvLocator = new ServiceLocator();
        ServiceLocator srvLocator = ServiceLocator.getInstance();
        try {
            Logger.debug(this, "findByPrimaryKey(), pk=" + pk);
            SimpleBaseDao dao = (SimpleBaseDao) model.getDaoType().newInstance();
            conn = srvLocator.getDSDBConnection();
            targetModel = (SimpleBaseVo) dao.findByPrimaryKey(pk, conn);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }
        return targetModel;
    }

    public SimpleBasePk createMaster(SimpleBaseVo model) throws CreateRecordException {
        Connection conn = null;
        SimpleBasePk pk = null;
        try {
            beforeCreate(model);
            getBizLogicTypeFromVo(model);
            if(bizLogic != null){
                bizLogic.bizLogicsBeforeCreate(model);
            }

            // ServiceLocator srvLocator = new ServiceLocator();
            ServiceLocator srvLocator = ServiceLocator.getInstance();

            UserTransaction userTrans = srvLocator.getUserTransaction();
            userTrans.begin();
            try {
                SimpleBaseDao dao = (SimpleBaseDao) model.getDaoType().newInstance();
                conn = srvLocator.getDSDBConnection();
                if(bizLogic != null){
                    bizLogic.genDocNo(model, conn);
                }
                model.assignKey(model.getPrimaryKey());
                beforeInsertModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsBeforeCreateModel(model, conn);
                }
                dao.insertModel(model, conn);
                afterInsertModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterCreateModel(model, conn);
                }
                userTrans.commit();
                afterCreate(model);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterCreate(model);
                }
                pk = (SimpleBasePk) model.getPrimaryKey();
                Logger.debug(this, "createMaster(), pk=" + pk);
            } catch (Exception e) {
                Logger.logExceptions(this, e);
                userTrans.rollback();
                throw e;
            }
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new CreateRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
            bizLogic = null;
        }
        return pk;
    }

    public void updateMaster(SimpleBaseVo model) throws ModifyRecordException {

        Connection conn = null;
        try {
            // AbstractPK pk = (AbstractPK) model.getPrimaryKey();
            // Logger.debug(this, "updateMaster(), pk=" + pk);
            beforeUpdate(model);
            getBizLogicTypeFromVo(model);
            if(bizLogic != null){
                bizLogic.bizLogicsBeforeUpdate(model);
            }
            
            // ServiceLocator srvLocator = new ServiceLocator();
            ServiceLocator srvLocator = ServiceLocator.getInstance();
            UserTransaction userTrans = srvLocator.getUserTransaction();
            userTrans.begin();
            try {
                SimpleBaseDao dao = (SimpleBaseDao) model.getDaoType().newInstance();
                conn = srvLocator.getDSDBConnection();
                //model.assignKey(model.getPrimaryKey());
                beforeUpdateModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsBeforeUpdateModel(model, conn);
                }
                dao.updateModel(model, conn);
                afterUpdateModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterUpdateModel(model, conn);
                }
                userTrans.commit();
                afterUpdate(model);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterUpdate(model);
                }
            } catch (Exception e) {
                Logger.logExceptions(this, e);
                srvLocator.userTransactionRollBack(userTrans);
                throw e;
            }
        } catch (java.lang.reflect.UndeclaredThrowableException ue) {
            Logger.logExceptions(this, ue);
            Logger.error(this, "updateMaster(), error: " + ue.getUndeclaredThrowable());
            throw new ModifyRecordException(ue.getMessage());
        } catch (javax.transaction.RollbackException traxe) {
            Logger.logExceptions(this, traxe);
            throw new ModifyRecordException(traxe.getMessage());
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new ModifyRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
            bizLogic = null;
        }
    }

    public void removeMaster(SimpleBaseVo model, SimpleBasePk pk) throws DeleteRecordException, FindRecordException {

        ServiceLocator srvLocator = ServiceLocator.getInstance();
        SimpleBaseDao dao = null;
        Connection conn = null;
        SimpleBaseVo targetModel = null;
        try {
            Logger.debug(this, "updateMaster(), pk=" + pk);
            beforeRemove(model);
            getBizLogicTypeFromVo(model);
            if(bizLogic != null){
                bizLogic.bizLogicsBeforeRemove(model);
            }            
            conn = srvLocator.getDSDBConnection();
            dao = (SimpleBaseDao) model.getDaoType().newInstance();
            targetModel = (SimpleBaseVo) dao.findByPrimaryKey(pk, conn);
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new FindRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null && !conn.isClosed())
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }
        try {
            UserTransaction userTrans = srvLocator.getUserTransaction();
            userTrans.begin();
            try {
                conn = srvLocator.getDSDBConnection();
                //beforeRemoveModel(targetModel, conn);
                beforeRemoveModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsBeforeRemoveModel(model, conn);
                }
                //dao.removeModel(targetModel, conn);
                dao.removeModel(model, conn);
                //afterRemoveModel(targetModel, conn);
                afterRemoveModel(model, conn);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterRemoveModel(model, conn);
                }
                userTrans.commit();
                //afterRemove(targetModel);
                afterRemove(model);
                if(bizLogic != null){
                    bizLogic.bizLogicsAfterRemove(model);
                } 
            } catch (Exception e) {
                Logger.logExceptions(this, e);
                srvLocator.userTransactionRollBack(userTrans);
                throw e;
            }
        } catch (javax.transaction.RollbackException traxe) {
            Logger.logExceptions(this, traxe);
            throw new DeleteRecordException(traxe.getMessage());
        } catch (Exception e) {
            Logger.logExceptions(this, e);
            throw new DeleteRecordException(e.getMessage());
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                Logger.logExceptions(this, e);
            }
        }
    }

//    public void updateBatch(Collection masterCollection) throws ModifyRecordException {
//
//        if (masterCollection == null || masterCollection.size() == 0)
//            return;
//        Connection conn = null;
//        try {
//            Logger.debug(this, "updateBatch(), " + sessionContext.getUserTransaction().getStatus());
//            ServiceLocator srvLocator = ServiceLocator.getInstance();
//            UserTransaction userTrans = srvLocator.getUserTransaction();
//            SimpleBaseDao dao = null;
//            Iterator iterator = masterCollection.iterator();
//            userTrans.begin();
//            try {
//                conn = srvLocator.getDSDBConnection();
//                while (iterator.hasNext()) {
//                    SimpleBaseVo masterModel = (SimpleBaseVo) iterator.next();
//                    if (dao == null) {
//                        dao = (SimpleBaseDao) masterModel.getDaoType().newInstance();
//                    }
//                    Logger.debug(this, "updateBatch(), pk= " + masterModel.getPrimaryKey() + ", exist="
//                            + masterModel.getIsExisting() + ", delete=" + masterModel.getIsDelete() + ", model="
//                            + masterModel.toString());
//                    if (masterModel.getIsExisting()) {
//                        if (!masterModel.getIsDelete()) {
//                            // Case 1. updates an existing record
//                            dao.updateModel(masterModel, conn);
//                        } else {
//                            // Case 2. deletes the whole branch
//                            dao.removeModel(masterModel, conn);
//                            iterator.remove();
//                        }
//                    } else {
//                        if (!masterModel.getIsDelete()) {
//                            // Case 3. inserts a record
//                            dao.insertModel(masterModel, conn);
//                        } else {
//                            iterator.remove();
//                        }
//                    }
//                } // _iterate_ over each master on MasterList
//                userTrans.commit();
//            } catch (Exception e) {
//                Logger.logExceptions(this, e);
//                srvLocator.userTransactionRollBack(userTrans);
//                throw new ModifyRecordException(e.getMessage());
//            }
//        } catch (java.lang.reflect.UndeclaredThrowableException ue) {
//            Logger.logExceptions(this, ue);
//            Logger.error(this, ue.getUndeclaredThrowable());
//            throw new ModifyRecordException(ue.getMessage());
//        } catch (javax.transaction.RollbackException traxe) {
//            Logger.logExceptions(this, traxe);
//            throw new ModifyRecordException(traxe.getMessage());
//        } catch (Exception e) {
//            Logger.logExceptions(this, e);
//            throw new ModifyRecordException(e.getMessage());
//        } finally {
//            try {
//                if (conn != null)
//                    conn.close();
//            } catch (Exception e) {
//                Logger.logExceptions(this, e);
//            }
//        }
//    }

    /**
    * @deprecated
    *
    */
    protected void beforeCreate(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterCreate(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void beforeUpdate(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterUpdate(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void beforeRemove(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterRemove(SimpleBaseVo model) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void beforeInsertModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterInsertModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void beforeUpdateModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterUpdateModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void beforeRemoveModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    /**
     * @deprecated
     *
     */
    protected void afterRemoveModel(SimpleBaseVo model, Connection conn) throws Exception {

    }

    public void ejbCreate() {

    }

    public void ejbRemove() {

    }

    public void ejbActivate() {

    }

    public void ejbPassivate() {

    }

    public void setSessionContext(SessionContext ctx) {

        this.sessionContext = ctx;
    }

}
